#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <linux/vt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/kd.h>
#include <linux/keyboard.h>

#include <unistd.h>
#include <time.h>
#include <linux/input.h>
#include <linux/uinput.h>

#define die(str, args...) do { \
        perror(str); \
        return -1; \
    } while(0)

#define FK_DEBUG(...) 


/* For compatibility with kernels having dates on 32 bits */
struct timeval_compat
{
  unsigned int tv_sec;
  long int tv_usec;
};

struct input_event_compat {
    struct timeval_compat time;
    unsigned short type;
    unsigned short code;
    unsigned int value;
};

static int uidev_fd;

int init_uinput(void)
{
  int fd;
  struct uinput_user_dev uidev;
  int i;

  fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
  if(fd < 0)
    die("/dev/uinput");

  if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
    die("error: ioctl");
  if(ioctl(fd, UI_SET_EVBIT, EV_REP) < 0)
    die("error: ioctl");
  if(ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0)
    die("error: ioctl");

  if(ioctl(fd, UI_SET_EVBIT, EV_REL) < 0)
    die("error: ioctl");
  if(ioctl(fd, UI_SET_RELBIT, REL_X) < 0)
    die("error: ioctl");
  if(ioctl(fd, UI_SET_RELBIT, REL_Y) < 0)
    die("error: ioctl");

  /* don't forget to add all the keys! */
  for(i=0; i<256; i++){
    if(ioctl(fd, UI_SET_KEYBIT, i) < 0)
      die("error: ioctl");
  }

  memset(&uidev, 0, sizeof(uidev));
  snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
  uidev.id.bustype = BUS_USB;
  uidev.id.vendor  = 0x1;
  uidev.id.product = 0x1;
  uidev.id.version = 1;

  /*if(write(fd, &uidev, sizeof(uidev)) < 0)
    die("error: write");*/

  if(ioctl(fd, UI_DEV_SETUP, &uidev) < 0)
	die("error: ioctl");

  if(ioctl(fd, UI_DEV_CREATE) < 0)
    die("error: ioctl");

  uidev_fd = fd;

//   sleep(1);

  return 0;
}

int close_uinput(void)
{
//   sleep(2);

  if(ioctl(uidev_fd, UI_DEV_DESTROY) < 0)
    die("error: ioctl");

  close(uidev_fd);

  return 0;
}

static int sendSync(void)
{
  FK_DEBUG("sendSync\n");
  //memset(&uidev_ev, 0, sizeof(struct input_event));
  struct input_event ie;
  ie.type = EV_SYN;
  ie.code = SYN_REPORT;
  ie.value = 0;
  ie.time.tv_sec = 0;
  ie.time.tv_usec = 0;
  if(write(uidev_fd, &ie, sizeof(struct input_event)) < 0)
    die("error: sendSync - write");

  return 0;
}

int sendKey(int key, int value)
{
  struct input_event_compat ie;
  //memset(&uidev_ev, 0, sizeof(struct input_event));
  //gettimeofday(&uidev_ev.time, NULL);
  ie.type = EV_KEY;
  ie.code = key;
  ie.value = value;
  ie.time.tv_sec = 0;
  ie.time.tv_usec = 0;
  FK_DEBUG("sendKey: %d = %d\n", key, value);
  if(write(uidev_fd, &ie, sizeof(struct input_event_compat)) < 0)
    die("error: write");

  sendSync();

  return 0;
}